﻿using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

namespace SoarD.Pandora.Console
{
    [DisallowMultipleComponent]
    public partial class PdrConsoleWindow : MonoBehaviour
    {
        internal static Rect DefaultIconRect;
        internal static readonly Rect DefaultWindowRect = new Rect(0, 0, Screen.width, Screen.height);
        internal static readonly float DefaultWindowScale = 1f;
        internal static Vector2 ButtonSize = new Vector2(100, 50);
        internal static Vector2 ToggleSize = new Vector2(90, 40);

        private static int spaceHeight = 5;
        static GUIStyle labelStyle;
        static GUIStyle buttonStyle;
        static GUIStyle toggleStyle;
        static GUIStyle windowStyle;

        [SerializeField]
        private bool m_ShowFullWindow;

        private IConsoleManager _mConsoleManager;
        private Rect m_DragRect = new Rect(0f, 0f, float.MaxValue, 125f);
        private Rect m_IconRect;
        private Rect m_WindowRect = DefaultWindowRect;
        private Image PdrMask;

        [SerializeField]
        private LogWindow _mLogWindow = new LogWindow();
        private SystemInfoWindow m_SystemInfoWindow = new SystemInfoWindow();
        private GraphicsInfoWindow m_GraphicsInfoWindow = new GraphicsInfoWindow();
        private ScreenInfoWindow m_ScreenInfoWindow = new ScreenInfoWindow();
        private ProfilerInfoWindow m_ProfilerInfoWindow = new ProfilerInfoWindow();
        private RunTimeMemoryWindow<Object> m_AllMemoryWindow = new RunTimeMemoryWindow<Object>();
        private RunTimeMemoryWindow<Texture> m_TextureMemoryWindow = new RunTimeMemoryWindow<Texture>();
        private RunTimeMemoryWindow<Mesh> m_MeshMemoryWindow = new RunTimeMemoryWindow<Mesh>();
        private RunTimeMemoryWindow<Material> m_MaterialMemoryWindow = new RunTimeMemoryWindow<Material>();
        private RunTimeMemoryWindow<AnimationClip> m_AnimationClipMemoryWindow = new RunTimeMemoryWindow<AnimationClip>();
        private RunTimeMemoryWindow<AudioClip> m_AudioClipMemoryWindow = new RunTimeMemoryWindow<AudioClip>();
        private RunTimeMemoryWindow<Font> m_FontMemoryWindow = new RunTimeMemoryWindow<Font>();
        private RunTimeMemoryWindow<GameObject> m_GameObjectMemoryWindow = new RunTimeMemoryWindow<GameObject>();
        private RunTimeMemoryWindow<Component> m_ComponentMemoryWindow = new RunTimeMemoryWindow<Component>();

        #region Property
        public float UpdateInterval = 0.5f;
        float m_lastInterval;
        int m_fps;
        int m_frames;
        public static bool ShowLuaMemory;
        public static int luaMemorySize;
        public static int luaMemoryDelta;
        private int m_luaMemoryLast;
        private string KEY = "TogglePandora";
        #endregion

        void Start()
        {
            _mConsoleManager = new ConsoleManager();
            RegisterAllWindows();
        }

        public virtual void RegisterAllWindows()
        {
            RegisterDebuggerWindow("控制台", _mLogWindow);
            RegisterDebuggerWindow("设备信息/系统信息", m_SystemInfoWindow);
            RegisterDebuggerWindow("设备信息/显卡信息", m_GraphicsInfoWindow);
            RegisterDebuggerWindow("设备信息/屏幕信息", m_ScreenInfoWindow);
            RegisterDebuggerWindow("分析/Profiler", m_ProfilerInfoWindow);
            RegisterDebuggerWindow("分析/内存/All", m_AllMemoryWindow);
            RegisterDebuggerWindow("分析/内存/贴图", m_TextureMemoryWindow);
            RegisterDebuggerWindow("分析/内存/GO", m_GameObjectMemoryWindow);
            RegisterDebuggerWindow("分析/内存/脚本", m_ComponentMemoryWindow);
            RegisterDebuggerWindow("分析/内存/网格", m_MeshMemoryWindow);
            RegisterDebuggerWindow("分析/内存/材质", m_MaterialMemoryWindow);
            RegisterDebuggerWindow("分析/内存/动画", m_AnimationClipMemoryWindow);
            RegisterDebuggerWindow("分析/内存/音效", m_AudioClipMemoryWindow);
            RegisterDebuggerWindow("分析/内存/字体", m_FontMemoryWindow);
        }

        public void RegisterDebuggerWindow(string path, IConsoleWindow consoleWindow, params object[] args)
        {
            _mConsoleManager.RegisterConsoleWindow(path, consoleWindow, args);
        }

        void OnGUI()
        {
            //bool bPandoraSetting = PlayerPrefs.HasKey(KEY);
            //if (!bPandoraSetting || (bPandoraSetting && PlayerPrefs.GetInt(KEY) == 0))
            //    return;

            InitShow();
            if (m_ShowFullWindow)
            {
                m_WindowRect = GUILayout.Window(0, m_WindowRect, DrawWindow, "<b>Pandora Console</b>", windowStyle);
            }
            else
            {
                m_IconRect = GUILayout.Window(0, m_IconRect, DrawDebuggerWindowIcon, "<b>Pandora</b>", windowStyle);
                WindowAnchor();
            }
        }

        void InitShow()
        {
            if (buttonStyle != null) return;
            int commonFontSize = 15;
            spaceHeight = 5;
            buttonStyle = GUI.skin.button;
            toggleStyle = GUI.skin.toggle;
            windowStyle = GUI.skin.window;
            labelStyle = GUI.skin.label;
            if (Screen.width > 768)
            {
                DefaultIconRect = new Rect(Screen.width - 240, Screen.height / 2.0f, 120, 120);
                ButtonSize = ButtonSize * 2;
                ToggleSize = ToggleSize * 2;
                windowStyle.border.top = 12;
                windowStyle.padding.top = 30;
                commonFontSize = 30;
                spaceHeight = 15;
                toggleStyle.padding.top = 10;
                toggleStyle.border.top = 12;
                toggleStyle.border.left = 14;
                toggleStyle.border.top = 0;
                toggleStyle.padding.left = 15;
                TitleWidth = 340;
            }
            else if (Screen.width > 640)
            {
                DefaultIconRect = new Rect(Screen.width - 200, Screen.height / 2.0f, 100, 80);
                spaceHeight = 10;
            }
            else
            {
                DefaultIconRect = new Rect(Screen.width - 120, Screen.height / 2.0f, 60, 60);
            }
            buttonStyle.fixedHeight = ButtonSize.y;
            windowStyle.fontSize = commonFontSize;
            buttonStyle.fontSize = commonFontSize;
            toggleStyle.fontSize = commonFontSize;
            labelStyle.fontSize = commonFontSize;
            toggleStyle.alignment = TextAnchor.MiddleCenter;
            m_IconRect = DefaultIconRect;

            if (PdrMask == null)
            {
                GameObject image = new GameObject("PdrMask");
                image.transform.parent = Config.Instance.MainUIRoot;
                image.transform.localScale = Vector3.one;
                image.transform.localPosition = Vector3.zero;

                PdrMask = image.AddComponent<Image>();
                PdrMask.raycastTarget = true;
                PdrMask.color = new Color(0, 0, 0.01f, 1);

                RectTransform rect = PdrMask.rectTransform;
                rect.anchorMin = Vector2.zero;
                rect.anchorMax = Vector2.one;
                rect.offsetMax = new Vector2(0, 0);
                rect.offsetMin = new Vector2(0, 0);
                PdrMask.gameObject.SetActive(false);
            }

            PdrAnalyzer.CaclScore();
        }

        private void DrawWindow(int windowId)
        {
            DrawDebuggerWindowGroup(_mConsoleManager.ConsoleWindowRoot);
            GUI.DragWindow(m_DragRect);
        }

        private void DrawDebuggerWindowGroup(IConsoleWindowGroup consoleWindowGroup)
        {
            if (consoleWindowGroup == null)
            {
                return;
            }
            GUILayout.Space(spaceHeight);
            List<string> names = new List<string>();
            string[] debuggerWindowNames = consoleWindowGroup.GetWindowNames();
            for (int i = 0; i < debuggerWindowNames.Length; i++)
            {
                names.Add(string.Format("<b>{0}</b>", debuggerWindowNames[i]));
            }

            if (consoleWindowGroup == _mConsoleManager.ConsoleWindowRoot)
            {
                names.Add("<b>Close</b>");
            }

            int toolbarIndex = GUILayout.Toolbar(consoleWindowGroup.SelectedIndex, names.ToArray(), buttonStyle, GUILayout.Height(ButtonSize.y), GUILayout.MaxWidth(Screen.width));
            if (toolbarIndex >= consoleWindowGroup.WindowCount)
            {
                m_ShowFullWindow = false;
                PdrMask.gameObject.SetActive(false);
                return;
            }

            if (consoleWindowGroup.SelectedIndex != toolbarIndex)
            {
                consoleWindowGroup.SelectedWindow.OnLeave();
                consoleWindowGroup.SelectedIndex = toolbarIndex;
                consoleWindowGroup.SelectedWindow.OnEnter();
            }

            IConsoleWindowGroup subConsoleWindowGroup = consoleWindowGroup.SelectedWindow as IConsoleWindowGroup;
            if (subConsoleWindowGroup != null)
            {
                DrawDebuggerWindowGroup(subConsoleWindowGroup);
            }

            if (consoleWindowGroup.SelectedWindow != null)
            {
                GUILayout.Space(spaceHeight);
                consoleWindowGroup.SelectedWindow.OnDraw();
            }
        }

        private void DrawDebuggerWindowIcon(int windowId)
        {
            GUILayout.Space(spaceHeight * 2);
            Color32 color;
            _mLogWindow.RefreshCount();
            if (_mLogWindow.FatalCount > 0)
            {
                color = _mLogWindow.GetLogStringColor(LogType.Exception);
            }
            else if (_mLogWindow.ErrorCount > 0)
            {
                color = _mLogWindow.GetLogStringColor(LogType.Error);
            }
            else if (_mLogWindow.WarningCount > 0)
            {
                color = _mLogWindow.GetLogStringColor(LogType.Warning);
            }
            else
            {
                color = _mLogWindow.GetLogStringColor(LogType.Log);
            }

            string title = string.Format("<color=#{0}{1}{2}{3}><b>FPS: {4}</b></color>", color.r.ToString("x2"), color.g.ToString("x2"), color.b.ToString("x2"), color.a.ToString("x2"), m_fps);
            if (GUILayout.Button(title, buttonStyle, GUILayout.Width(ButtonSize.x), GUILayout.Height(ButtonSize.y)))
            {
                m_ShowFullWindow = true;
                PdrMask.transform.SetAsLastSibling();
                PdrMask.gameObject.SetActive(true);
            }
            GUI.DragWindow(m_DragRect);
        }

        void Update()
        {
            ++m_frames;
            float timeNow = Time.realtimeSinceStartup;
            OnPreUpdate();
            if (timeNow > m_lastInterval + UpdateInterval)
            {
                luaMemoryDelta = luaMemorySize - m_luaMemoryLast;
                m_luaMemoryLast = luaMemorySize;

                m_fps = (int)(m_frames / (timeNow - m_lastInterval));
                m_frames = 0;
                m_lastInterval = timeNow;
            }
        }

        #region 窗口停靠
        private float AnchorWidth = 10;
        private int Anchor;
        private float AnchorPos;

        private void WindowAnchor()
        {
            if (Input.GetMouseButtonDown(0))
            {
                Anchor = 0;
            }
            if (Anchor == 0 && Input.GetMouseButtonUp(0))
            {
                if (m_IconRect.x + m_IconRect.width >= Screen.width)
                {
                    Anchor = 1;
                    AnchorPos = Screen.width - AnchorWidth;
                }
                else if (m_IconRect.x <= 0)
                {
                    Anchor = 2;
                    AnchorPos = AnchorWidth - m_IconRect.width;
                }
            }
        }

        void LateUpdate()
        {
            if (Anchor != 0 && Mathf.Abs(AnchorPos) > float.Epsilon)
            {
                m_IconRect.x = Mathf.Lerp(m_IconRect.x, AnchorPos, Time.deltaTime * 5);
                if (Mathf.Abs(m_IconRect.x - AnchorPos) < 0.1f)
                {
                    m_IconRect.x = AnchorPos;
                    AnchorPos = 0;
                }
            }
        }
        #endregion

        public virtual void OnPreUpdate() { }
    }
}